package manager

import (
	"github.com/tianjigames/fairy/constants"
	"github.com/tianjigames/fairy/model"
	"github.com/tianjigames/fairy/template"
	"github.com/topfreegames/pitaya/logger"
	"math"
	"sync"
)

const (
	//逻辑id定义
	SKillLogicInvalid = 0 //无效
	SkillLogicAttackBase = 1 //基础攻击
	SkillLogicAttackSec = 2 //2端技能
	SkillLogicAttackThird = 3 //3段技能
	SkillLogicAttackFour = 4 //4段技能
	SkillLogicAttackFiv = 5 //5段及鞥
	SkillLogicAttackSix = 6 //6段技能
	SkillLogicAttackCombo = 7

	//被动技能的及鞥效果
	SkillLogicAttackPassive = 8 //被动及鞥呢对主动技能影响
	SkillLogicAttackBuff = 9 //buff触发被动及鞥呢
	SkillLogicAttackAttr = 10 //被动技能对属性的影响
	SkillLogicAttackXP = 11 //xp技能
	SKillLogicNum = SkillLogicAttackXP + 1

	//技能选择的类型定义
	ChooseLogicInvalid = -1
	ChoosLogicTaget = 0 //技能释放需要目标
	ChooseLogicNum = 1
)

var (
	SkillLogicManager *skillLogicManager
	skillLogicManagerOnce sync.Once
)

type (
	SkillLogic interface {
		GetLogicID() int                                                                                  //技能对象在技能管理器中id
		OnActive(fromObj *model.CharObj) bool                                                             //技能是否激活
		GetAttr(fromObj model.CharObj,mPassiveSkillBase *template.SkillBase,attrFlag *constants.AttrFlag) int //被动技能对属性值的影响
		OnMarkAttrFlag(fromObj model.CharObj,mPassiveSkillBase *template.SkillBase)
	}

	SkillChooseLogic interface {
		UnitChooseLogic(pCharObj model.CharObj,nSkillId int)
		CanUseSkill(pCharObj model.CharObj,nSkillId int)
	}

	BaseSkillLogic struct {
	}

	skillLogicManager struct {
		BaseManager
		sMotionLogic []SkillLogic
		sSkillChooseLogic []SkillChooseLogic
	}

	//被动技能对属性的影响逻辑
	SkillAttackAttrLogic struct {
		BaseSkillLogic
	}
)

/**
技能逻辑管理器
 */
func NewSkillLogicManager() *skillLogicManager {
	skillLogicManagerOnce.Do(func() {
		SkillLogicManager = &skillLogicManager{
			sMotionLogic: make([]SkillLogic,SKillLogicNum),
			sSkillChooseLogic: make([]SkillChooseLogic,ChooseLogicNum),
		}

		//todo：设置其他技能的释放逻辑
		SkillLogicManager.sMotionLogic[SkillLogicAttackAttr] = &SkillAttackAttrLogic{}
	})

	return SkillLogicManager
}

/**
获取某个技能逻辑对象
 */
func (p *skillLogicManager) GetSkillLogic(nLogicID int) SkillLogic {
	if nLogicID > SKillLogicInvalid && nLogicID < SKillLogicNum {
		return p.sMotionLogic[nLogicID]
	}
	return nil
}

func (p *BaseSkillLogic) GetLogicID() int {
	return SKillLogicInvalid
}

func (p *BaseSkillLogic) OnActive(fromObj *model.CharObj) bool {
	return true
}

func (p *BaseSkillLogic)GetAttr(fromObj model.CharObj,mPassiveSkillBase *template.SkillBase,attrFlag *constants.AttrFlag) int {
	return 0
}

func (p *BaseSkillLogic) OnMarkAttrFlag(fromObj model.CharObj,mPassiveSkillBase *template.SkillBase)  {

}

func (p *SkillAttackAttrLogic) GetLogicID() int {
	return SkillLogicAttackAttr
}

/**
被动技能对属性的影响逻辑
 */
func (p *SkillAttackAttrLogic)GetAttr(fromObj model.CharObj,mPassiveSkillBase *template.SkillBase,attrFlag *constants.AttrFlag) int {
	if fromObj == nil || mPassiveSkillBase == nil || attrFlag == nil{
		return 0
	}

	attrIds := mPassiveSkillBase.Buff1
	if attrIds != nil && len(attrIds) == 1 && attrIds[0] == int(constants.AttrAttackAll) {//对素有的攻击类属性有影响
		if *attrFlag == constants.AttrAttackPhy || *attrFlag == constants.AttrAttackPoison {//物理、法术攻击
			typ := mPassiveSkillBase.Buff2[0] //加成类型
			value := mPassiveSkillBase.Buff3[0] //加成值
			value = LoadPlayerInfoManager.GetAttrResult(model.GetRefixTypeByValue(typ),value,fromObj.GetBaseAttr(attrFlag))
			logger.Log.Infof("SkillAttackLogic allAttack playerId:%d,skillId:%s,attrFlag:%d,value:%d",
				fromObj.GetId(),mPassiveSkillBase.Id,int(*attrFlag),value)
			return value
		}
	}

	if !p.InClude(int(*attrFlag),attrIds) {
		return 0
	}

	modifyTypes := mPassiveSkillBase.Buff2
	modifyValues := mPassiveSkillBase.Buff3
	length := math.Min(float64(len(attrIds)),math.Min(float64(len(modifyTypes)),float64(len(modifyValues))))

	nBaseAttr := fromObj.GetBaseAttr(attrFlag)
	value := 0
	for i:=0;i<int(length);i++ {
		if attrIds[i] == int(*attrFlag) {//基本加成
			value += LoadPlayerInfoManager.GetAttrResult(model.GetRefixTypeByValue(modifyTypes[i]),
				modifyValues[i],fromObj.GetBaseAttr(attrFlag))
		}else {
			value += LoadPlayerInfoManager.CheckSpecialAttrByFlag(attrFlag,constants.GetAttrFlagByValue(attrIds[i]),model.GetRefixTypeByValue(modifyTypes[i]),modifyValues[i],nBaseAttr)
		}
	}
	return value
}

func (p *SkillAttackAttrLogic) OnMarkAttrFlag(fromObj model.CharObj,mPassiveSkillBase *template.SkillBase)  {
	if fromObj == nil || mPassiveSkillBase == nil {
		return
	}

	attrIds := mPassiveSkillBase.Buff1
	modifyTypes := mPassiveSkillBase.Buff2
	modifyValues := mPassiveSkillBase.Buff3

	length := math.Min(float64(len(attrIds)),math.Min(float64(len(modifyTypes)),float64(len(modifyValues))))
	for i:=0;i<int(length);i++ {
		if !CalCulateUtil.IsValidAttrId(attrIds[i]){
			continue
		}

		fromObj.SetAttrFlag(constants.GetAttrFlagByValue(attrIds[i]),true)
	}
}

/**
判断属性列表中是否包含某个属性
 */
func (p *SkillAttackAttrLogic) InClude(attrId int,attrTypes []int) bool {
	for _,v := range attrTypes {
		if attrId == v {
			return true
		}
	}

	return false
}